/**
 * 一： setInterval原理---------
 * 延时一段时间后，将任务push到任务队列中排队执行；
 * 在每次把任务 push 到任务队列前，都要进行一下判断(看上次的任务是否仍在队列中，如果有则不添加，没有则添加)。
 * 二： setInterval弊端----------
 * 1.setInterval对自己调用的代码是否报错漠不关心。即使调用的代码报错了，它依然会持续的调用下去
 * 2.setInterval无视网络延迟。在使用ajax轮询服务器是否有新数据时，必定会有一些人会使用setInterval，然而无论网络状况如何，它都会去一遍又一遍的发送请求，如果网络状况不良，一个请求发出，还没有返回结果，它会坚持不懈的继续发送请求，最后导致的结果就是请求堆积。
 * 3.setInterval并不定时。如果它调用的代码执行的时间小于定时的时间，它会跳过调用，这就导致无法按照你需要的执行次数或无法得到你想要的结果。
 * 4.累积效应，在重复时间内要执行的操作耗时比重复时间长，会快速触发操作，损耗性能，效果差
 * 5. 一些浏览器还会有不同的问题，比如低版本火狐，在滚动条滚动时，计时器会停止执行，等滚动条停止时，事件一次触发，这段事件累计的计时器
 * 6.当页面中有计时器，把页面放到后台一段时间，计时器会暂停，再切回到页面，这段时间累计的计时器会高速的执行（比如W3school）
 * 三： setTimeout的优势
 * setTimeout是异步执行的，堆栈中碰到setTimeout会交给浏览器内核处理，等待setTimeout达到触发条件（即设定的时间），再返回给执行队列。
 * 简而言之，就是计时的这个操作是在浏览器端进行的，在计时完成后，将settimeout中的操作放入事件队列中。
 * @description 使用setTimeout代替 setInterval
 * @param fn
 * @param delay
 * @returns {{clear(): void}}
 */
export function setIntervalByTimeout (fn, delay = 1000) {
  let timer = null;
  function inside () {
    // console.log(new Date().toLocaleString()); // 打印看看时间
    clearTimeout(timer);
    fn && fn();
    timer = setTimeout(inside, delay);
  }
  timer = setTimeout(inside, delay);
  return {
    clear () {
      clearTimeout(timer);
    }
  };
}


/**
 * 倒计时
 * @param fn 回调
 * @param duration 倒计时多久
 */
export function justifyInterval (fn, duration = 30000) {
  let count = 0, timer = null;
  let start = new Date().getTime();
  // 避免递归没有退出条件出现爆栈，实际项目可以是页面退出时清空定时器
  let stop = false;
  // 计算需对齐的秒数
  const firstTimeout = 1000 - start % 1000;
  function countTime () {
    const temp = new Date().getTime();
    stop = (temp - start) >= duration;
    const innerDelay = temp - (start + count * 1000);
    count++;
    const intervalGap = 1000 - innerDelay;
    const timeout = intervalGap > 0 ? intervalGap : 0;
    console.log(`执行时间多久了-----${temp - start}`);
    timer = setTimeout(() => {
      if (!stop) {
        fn && fn(temp - start);
        countTime();
      }
    }, timeout);
  }
  setTimeout(() => {
    // 将开始时间调整为整秒后再开始计时
    start = start + firstTimeout;
    countTime();
  }, firstTimeout);
  return {
    clear () {
      stop = true;
      clearTimeout(timer);
      timer = null;
    }
  };
}
